#include "stdafx.h"

#include "json/jsoncpp/assertions.hpp"
#include "json/jsoncpp/reader.hpp"
#include "json/jsoncpp/value.hpp"
#include "json/jsoncpp/tool.hpp"
#include <utility>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <istream>
#include <sstream>
#include <memory>
#include <set>

#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
#define snprintf _snprintf
#endif

#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
// Disable warning about strdup being deprecated.
#pragma warning(disable : 4996)
#endif

static int const stackLimit_g = 1000;
static int       stackDepth_g = 0;  // see readValue()

namespace JHCPP
{
	namespace json
	{
		namespace jsoncpp
		{
		#if __cplusplus >= 201103L
			typedef std::unique_ptr<CharReader> CharReaderPtr;
		#else
			typedef std::auto_ptr<CharReader>   CharReaderPtr;
		#endif

			// Implementation of class Features
			// ////////////////////////////////

			Features::Features()
				: m_allowComments(true), m_strictRoot(false),
				m_allowDroppedNullPlaceholders(false), m_allowNumericKeys(false) {}

			Features Features::all() { return Features(); }

			Features Features::strictMode() 
			{
				Features features;
				features.m_allowComments = false;
				features.m_strictRoot = true;
				features.m_allowDroppedNullPlaceholders = false;
				features.m_allowNumericKeys = false;
				return features;
			}

			// Implementation of class Reader
			// ////////////////////////////////

			static bool containsNewLine(Reader::Location begin, Reader::Location end) 
			{
				for (; begin < end; ++begin)
					if (*begin == '\n' || *begin == '\r')
						return true;
				return false;
			}

			// Class Reader
			// //////////////////////////////////////////////////////////////////

			Reader::Reader()
				: m_errors(), m_document(), m_begin(), m_end(), m_current(), m_lastValueEnd(),
				m_lastValue(), m_commentsBefore(), m_features(Features::all()),
				m_collectComments() {}

			Reader::Reader(const Features& features)
				: m_errors(), m_document(), m_begin(), m_end(), m_current(), m_lastValueEnd(),
				m_lastValue(), m_commentsBefore(), m_features(features), m_collectComments() {
			}

			bool Reader::parse(const std::string& document, Value& root, bool collectComments) 
			{
					m_document = document;
					const char* begin = m_document.c_str();
					const char* end = begin + m_document.length();
					return parse(begin, end, root, collectComments);
			}

			bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
				// std::istream_iterator<char> begin(sin);
				// std::istream_iterator<char> end;
				// Those would allow streamed input from a file, if parse() were a
				// template function.

				// Since std::string is reference-counted, this at least does not
				// create an extra copy.
				std::string doc;
				std::getline(sin, doc, (char)EOF);
				return parse(doc, root, collectComments);
			}

			bool Reader::parse(const char* beginDoc,
				const char* endDoc,
				Value& root,
				bool collectComments) {
					if (!m_features.m_allowComments) {
						collectComments = false;
					}

					m_begin = beginDoc;
					m_end = endDoc;
					m_collectComments = collectComments;
					m_current = m_begin;
					m_lastValueEnd = 0;
					m_lastValue = 0;
					m_commentsBefore = "";
					m_errors.clear();
					while (!m_nodes.empty())
						m_nodes.pop();
					m_nodes.push(&root);

					stackDepth_g = 0;  // Yes, this is bad coding, but options are limited.
					bool successful = readValue();
					Token token;
					skipCommentTokens(token);
					if (m_collectComments && !m_commentsBefore.empty())
						root.setComment(m_commentsBefore, commentAfter);
					if (m_features.m_strictRoot) {
						if (!root.isArray() && !root.isObject()) {
							// Set error location to start of doc, ideally should be first token found
							// in doc
							token.m_type = tokenError;
							token.m_start = beginDoc;
							token.m_end = endDoc;
							addError(
								"A valid JSON document must be either an array or an object value.",
								token);
							return false;
						}
					}
					return successful;
			}

			bool Reader::readValue() {
				// This is a non-reentrant way to support a stackLimit. Terrible!
				// But this deprecated class has a security problem: Bad input can
				// cause a seg-fault. This seems like a fair, binary-compatible way
				// to prevent the problem.
				if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
				++stackDepth_g;

				Token token;
				skipCommentTokens(token);
				bool successful = true;

				if (m_collectComments && !m_commentsBefore.empty()) {
					currentValue().setComment(m_commentsBefore, commentBefore);
					m_commentsBefore = "";
				}

				switch (token.m_type) {
  case tokenObjectBegin:
	  successful = readObject(token);
	  currentValue().setOffsetLimit(m_current - m_begin);
	  break;
  case tokenArrayBegin:
	  successful = readArray(token);
	  currentValue().setOffsetLimit(m_current - m_begin);
	  break;
  case tokenNumber:
	  successful = decodeNumber(token);
	  break;
  case tokenString:
	  successful = decodeString(token);
	  break;
  case tokenTrue:
	  {
		  Value v(true);
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(token.m_start - m_begin);
		  currentValue().setOffsetLimit(token.m_end - m_begin);
	  }
	  break;
  case tokenFalse:
	  {
		  Value v(false);
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(token.m_start - m_begin);
		  currentValue().setOffsetLimit(token.m_end - m_begin);
	  }
	  break;
  case tokenNull:
	  {
		  Value v;
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(token.m_start - m_begin);
		  currentValue().setOffsetLimit(token.m_end - m_begin);
	  }
	  break;
  case tokenArraySeparator:
  case tokenObjectEnd:
  case tokenArrayEnd:
	  if (m_features.m_allowDroppedNullPlaceholders) {
		  // "Un-read" the current token and mark the current value as a null
		  // token.
		  m_current--;
		  Value v;
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(m_current - m_begin - 1);
		  currentValue().setOffsetLimit(m_current - m_begin);
		  break;
	  } // Else, fall through...
  default:
	  currentValue().setOffsetStart(token.m_start - m_begin);
	  currentValue().setOffsetLimit(token.m_end - m_begin);
	  return addError("Syntax error: value, object or array expected.", token);
				}

				if (m_collectComments) {
					m_lastValueEnd = m_current;
					m_lastValue = &currentValue();
				}

				--stackDepth_g;
				return successful;
			}

			void Reader::skipCommentTokens(Token& token) {
				if (m_features.m_allowComments) {
					do {
						readToken(token);
					} while (token.m_type == tokenComment);
				} else {
					readToken(token);
				}
			}

			bool Reader::readToken(Token& token) {
				skipSpaces();
				token.m_start = m_current;
				Char c = getNextChar();
				bool ok = true;
				switch (c) {
  case '{':
	  token.m_type = tokenObjectBegin;
	  break;
  case '}':
	  token.m_type = tokenObjectEnd;
	  break;
  case '[':
	  token.m_type = tokenArrayBegin;
	  break;
  case ']':
	  token.m_type = tokenArrayEnd;
	  break;
  case '"':
	  token.m_type = tokenString;
	  ok = readString();
	  break;
  case '/':
	  token.m_type = tokenComment;
	  ok = readComment();
	  break;
  case '0':
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9':
  case '-':
	  token.m_type = tokenNumber;
	  readNumber();
	  break;
  case 't':
	  token.m_type = tokenTrue;
	  ok = match("rue", 3);
	  break;
  case 'f':
	  token.m_type = tokenFalse;
	  ok = match("alse", 4);
	  break;
  case 'n':
	  token.m_type = tokenNull;
	  ok = match("ull", 3);
	  break;
  case ',':
	  token.m_type = tokenArraySeparator;
	  break;
  case ':':
	  token.m_type = tokenMemberSeparator;
	  break;
  case 0:
	  token.m_type = tokenEndOfStream;
	  break;
  default:
	  ok = false;
	  break;
				}
				if (!ok)
					token.m_type = tokenError;
				token.m_end = m_current;
				return true;
			}

			void Reader::skipSpaces() {
				while (m_current != m_end) {
					Char c = *m_current;
					if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
						++m_current;
					else
						break;
				}
			}

			bool Reader::match(Location pattern, int patternLength) {
				if (m_end - m_current < patternLength)
					return false;
				int index = patternLength;
				while (index--)
					if (m_current[index] != pattern[index])
						return false;
				m_current += patternLength;
				return true;
			}

			bool Reader::readComment() {
				Location commentBegin = m_current - 1;
				Char c = getNextChar();
				bool successful = false;
				if (c == '*')
					successful = readCStyleComment();
				else if (c == '/')
					successful = readCppStyleComment();
				if (!successful)
					return false;

				if (m_collectComments) {
					CommentPlacement placement = commentBefore;
					if (m_lastValueEnd && !containsNewLine(m_lastValueEnd, commentBegin)) {
						if (c != '*' || !containsNewLine(commentBegin, m_current))
							placement = commentAfterOnSameLine;
					}

					addComment(commentBegin, m_current, placement);
				}
				return true;
			}

			static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
				std::string normalized;
				normalized.reserve(end - begin);
				Reader::Location current = begin;
				while (current != end) {
					char c = *current++;
					if (c == '\r') {
						if (current != end && *current == '\n')
							// convert dos EOL
							++current;
						// convert Mac EOL
						normalized += '\n';
					} else {
						normalized += c;
					}
				}
				return normalized;
			}

			void
				Reader::addComment(Location begin, Location end, CommentPlacement placement) {
					assert(m_collectComments);
					const std::string& normalized = normalizeEOL(begin, end);
					if (placement == commentAfterOnSameLine) {
						assert(m_lastValue != 0);
						m_lastValue->setComment(normalized, placement);
					} else {
						m_commentsBefore += normalized;
					}
			}

			bool Reader::readCStyleComment() {
				while (m_current != m_end) {
					Char c = getNextChar();
					if (c == '*' && *m_current == '/')
						break;
				}
				return getNextChar() == '/';
			}

			bool Reader::readCppStyleComment() {
				while (m_current != m_end) {
					Char c = getNextChar();
					if (c == '\n')
						break;
					if (c == '\r') {
						// Consume DOS EOL. It will be normalized in addComment.
						if (m_current != m_end && *m_current == '\n')
							getNextChar();
						// Break on Moc OS 9 EOL.
						break;
					}
				}
				return true;
			}

			void Reader::readNumber() {
				const char *p = m_current;
				char c = '0'; // stopgap for already consumed character
				// integral part
				while (c >= '0' && c <= '9')
					c = (m_current = p) < m_end ? *p++ : 0;
				// fractional part
				if (c == '.') {
					c = (m_current = p) < m_end ? *p++ : 0;
					while (c >= '0' && c <= '9')
						c = (m_current = p) < m_end ? *p++ : 0;
				}
				// exponential part
				if (c == 'e' || c == 'E') {
					c = (m_current = p) < m_end ? *p++ : 0;
					if (c == '+' || c == '-')
						c = (m_current = p) < m_end ? *p++ : 0;
					while (c >= '0' && c <= '9')
						c = (m_current = p) < m_end ? *p++ : 0;
				}
			}

			bool Reader::readString() {
				Char c = 0;
				while (m_current != m_end) {
					c = getNextChar();
					if (c == '\\')
						getNextChar();
					else if (c == '"')
						break;
				}
				return c == '"';
			}

			bool Reader::readObject(Token& tokenStart) {
				Token tokenName;
				std::string name;
				Value init(objectValue);
				currentValue().swapPayload(init);
				currentValue().setOffsetStart(tokenStart.m_start - m_begin);
				while (readToken(tokenName)) {
					bool initialTokenOk = true;
					while (tokenName.m_type == tokenComment && initialTokenOk)
						initialTokenOk = readToken(tokenName);
					if (!initialTokenOk)
						break;
					if (tokenName.m_type == tokenObjectEnd && name.empty()) // empty object
						return true;
					name = "";
					if (tokenName.m_type == tokenString) {
						if (!decodeString(tokenName, name))
							return recoverFromError(tokenObjectEnd);
					} else if (tokenName.m_type == tokenNumber && m_features.m_allowNumericKeys) {
						Value numberName;
						if (!decodeNumber(tokenName, numberName))
							return recoverFromError(tokenObjectEnd);
						name = numberName.asString();
					} else {
						break;
					}

					Token colon;
					if (!readToken(colon) || colon.m_type != tokenMemberSeparator) {
						return addErrorAndRecover(
							"Missing ':' after object member name", colon, tokenObjectEnd);
					}
					Value& value = currentValue()[name];
					m_nodes.push(&value);
					bool ok = readValue();
					m_nodes.pop();
					if (!ok) // error already set
						return recoverFromError(tokenObjectEnd);

					Token comma;
					if (!readToken(comma) ||
						(comma.m_type != tokenObjectEnd && comma.m_type != tokenArraySeparator &&
						comma.m_type != tokenComment)) {
							return addErrorAndRecover(
								"Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
					}
					bool finalizeTokenOk = true;
					while (comma.m_type == tokenComment && finalizeTokenOk)
						finalizeTokenOk = readToken(comma);
					if (comma.m_type == tokenObjectEnd)
						return true;
				}
				return addErrorAndRecover(
					"Missing '}' or object member name", tokenName, tokenObjectEnd);
			}

			bool Reader::readArray(Token& tokenStart) {
				Value init(arrayValue);
				currentValue().swapPayload(init);
				currentValue().setOffsetStart(tokenStart.m_start - m_begin);
				skipSpaces();
				if (*m_current == ']') // empty array
				{
					Token endArray;
					readToken(endArray);
					return true;
				}
				int index = 0;
				for (;;) {
					Value& value = currentValue()[index++];
					m_nodes.push(&value);
					bool ok = readValue();
					m_nodes.pop();
					if (!ok) // error already set
						return recoverFromError(tokenArrayEnd);

					Token token;
					// Accept Comment after last item in the array.
					ok = readToken(token);
					while (token.m_type == tokenComment && ok) {
						ok = readToken(token);
					}
					bool badTokenType =
						(token.m_type != tokenArraySeparator && token.m_type != tokenArrayEnd);
					if (!ok || badTokenType) {
						return addErrorAndRecover(
							"Missing ',' or ']' in array declaration", token, tokenArrayEnd);
					}
					if (token.m_type == tokenArrayEnd)
						break;
				}
				return true;
			}

			bool Reader::decodeNumber(Token& token) {
				Value decoded;
				if (!decodeNumber(token, decoded))
					return false;
				currentValue().swapPayload(decoded);
				currentValue().setOffsetStart(token.m_start - m_begin);
				currentValue().setOffsetLimit(token.m_end - m_begin);
				return true;
			}

			bool Reader::decodeNumber(Token& token, Value& decoded) {
				// Attempts to parse the number as an integer. If the number is
				// larger than the maximum supported value of an integer then
				// we decode the number as a double.
				Location current = token.m_start;
				bool isNegative = *current == '-';
				if (isNegative)
					++current;
				// TODO: Help the compiler do the div and mod at compile time or get rid of them.
				Value::LargestUInt maxIntegerValue =
					isNegative ? Value::LargestUInt(-Value::minLargestInt)
					: Value::maxLargestUInt;
				Value::LargestUInt threshold = maxIntegerValue / 10;
				Value::LargestUInt value = 0;
				while (current < token.m_end) {
					Char c = *current++;
					if (c < '0' || c > '9')
						return decodeDouble(token, decoded);
					Value::UInt digit(c - '0');
					if (value >= threshold) {
						// We've hit or exceeded the max value divided by 10 (rounded down). If
						// a) we've only just touched the limit, b) this is the last digit, and
						// c) it's small enough to fit in that rounding delta, we're okay.
						// Otherwise treat this number as a double to avoid overflow.
						if (value > threshold || current != token.m_end ||
							digit > maxIntegerValue % 10) {
								return decodeDouble(token, decoded);
						}
					}
					value = value * 10 + digit;
				}
				if (isNegative)
					decoded = -Value::LargestInt(value);
				else if (value <= Value::LargestUInt(Value::maxInt))
					decoded = Value::LargestInt(value);
				else
					decoded = value;
				return true;
			}

			bool Reader::decodeDouble(Token& token) {
				Value decoded;
				if (!decodeDouble(token, decoded))
					return false;
				currentValue().swapPayload(decoded);
				currentValue().setOffsetStart(token.m_start - m_begin);
				currentValue().setOffsetLimit(token.m_end - m_begin);
				return true;
			}

			bool Reader::decodeDouble(Token& token, Value& decoded) {
				double value = 0;
				const int bufferSize = 32;
				int count;
				int length = int(token.m_end - token.m_start);

				// Sanity check to avoid buffer overflow exploits.
				if (length < 0) {
					return addError("Unable to parse token length", token);
				}

				// Avoid using a string constant for the format control string given to
				// sscanf, as this can cause hard to debug crashes on OS X. See here for more
				// info:
				//
				//     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
				char format[] = "%lf";

				if (length <= bufferSize) {
					Char buffer[bufferSize + 1];
					memcpy(buffer, token.m_start, length);
					buffer[length] = 0;
					count = sscanf(buffer, format, &value);
				} else {
					std::string buffer(token.m_start, token.m_end);
					count = sscanf(buffer.c_str(), format, &value);
				}

				if (count != 1)
					return addError("'" + std::string(token.m_start, token.m_end) +
					"' is not a number.",
					token);
				decoded = value;
				return true;
			}

			bool Reader::decodeString(Token& token) {
				std::string decoded_string;
				if (!decodeString(token, decoded_string))
					return false;
				Value decoded(decoded_string);
				currentValue().swapPayload(decoded);
				currentValue().setOffsetStart(token.m_start - m_begin);
				currentValue().setOffsetLimit(token.m_end - m_begin);
				return true;
			}

			bool Reader::decodeString(Token& token, std::string& decoded) {
				decoded.reserve(token.m_end - token.m_start - 2);
				Location current = token.m_start + 1; // skip '"'
				Location end = token.m_end - 1;       // do not include '"'
				while (current != end) {
					Char c = *current++;
					if (c == '"')
						break;
					else if (c == '\\') {
						if (current == end)
							return addError("Empty escape sequence in string", token, current);
						Char escape = *current++;
						switch (escape) {
	  case '"':
		  decoded += '"';
		  break;
	  case '/':
		  decoded += '/';
		  break;
	  case '\\':
		  decoded += '\\';
		  break;
	  case 'b':
		  decoded += '\b';
		  break;
	  case 'f':
		  decoded += '\f';
		  break;
	  case 'n':
		  decoded += '\n';
		  break;
	  case 'r':
		  decoded += '\r';
		  break;
	  case 't':
		  decoded += '\t';
		  break;
	  case 'u': {
		  unsigned int unicode;
		  if (!decodeUnicodeCodePoint(token, current, end, unicode))
			  return false;
		  decoded += codePointToUTF8(unicode);
				} break;
	  default:
		  return addError("Bad escape sequence in string", token, current);
						}
					} else {
						decoded += c;
					}
				}
				return true;
			}

			bool Reader::decodeUnicodeCodePoint(Token& token,
				Location& current,
				Location end,
				unsigned int& unicode) {

					if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
						return false;
					if (unicode >= 0xD800 && unicode <= 0xDBFF) {
						// surrogate pairs
						if (end - current < 6)
							return addError(
							"additional six characters expected to parse unicode surrogate pair.",
							token,
							current);
						unsigned int surrogatePair;
						if (*(current++) == '\\' && *(current++) == 'u') {
							if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
								unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
							} else
								return false;
						} else
							return addError("expecting another \\u token to begin the second half of "
							"a unicode surrogate pair",
							token,
							current);
					}
					return true;
			}

			bool Reader::decodeUnicodeEscapeSequence(Token& token,
				Location& current,
				Location end,
				unsigned int& unicode) {
					if (end - current < 4)
						return addError(
						"Bad unicode escape sequence in string: four digits expected.",
						token,
						current);
					unicode = 0;
					for (int index = 0; index < 4; ++index) {
						Char c = *current++;
						unicode *= 16;
						if (c >= '0' && c <= '9')
							unicode += c - '0';
						else if (c >= 'a' && c <= 'f')
							unicode += c - 'a' + 10;
						else if (c >= 'A' && c <= 'F')
							unicode += c - 'A' + 10;
						else
							return addError(
							"Bad unicode escape sequence in string: hexadecimal digit expected.",
							token,
							current);
					}
					return true;
			}

			bool
				Reader::addError(const std::string& message, Token& token, Location extra) {
					ErrorInfo info;
					info.m_token = token;
					info.m_message = message;
					info.m_extra = extra;
					m_errors.push_back(info);
					return false;
			}

			bool Reader::recoverFromError(TokenType skipUntilToken) {
				int errorCount = int(m_errors.size());
				Token skip;
				for (;;) {
					if (!readToken(skip))
						m_errors.resize(errorCount); // discard errors caused by recovery
					if (skip.m_type == skipUntilToken || skip.m_type == tokenEndOfStream)
						break;
				}
				m_errors.resize(errorCount);
				return false;
			}

			bool Reader::addErrorAndRecover(const std::string& message,
				Token& token,
				TokenType skipUntilToken) {
					addError(message, token);
					return recoverFromError(skipUntilToken);
			}

			Value& Reader::currentValue() { return *(m_nodes.top()); }

			Reader::Char Reader::getNextChar() {
				if (m_current == m_end)
					return 0;
				return *m_current++;
			}

			void Reader::getLocationLineAndColumn(Location location,
				int& line,
				int& column) const {
					Location current = m_begin;
					Location lastLineStart = current;
					line = 0;
					while (current < location && current != m_end) {
						Char c = *current++;
						if (c == '\r') {
							if (*current == '\n')
								++current;
							lastLineStart = current;
							++line;
						} else if (c == '\n') {
							lastLineStart = current;
							++line;
						}
					}
					// column & line start at 1
					column = int(location - lastLineStart) + 1;
					++line;
			}

			std::string Reader::getLocationLineAndColumn(Location location) const {
				int line, column;
				getLocationLineAndColumn(location, line, column);
				char buffer[18 + 16 + 16 + 1];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
#if defined(WINCE)
				_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#else
				sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
#else
				snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
				return buffer;
			}

			// Deprecated. Preserved for backward compatibility
			std::string Reader::getFormatedErrorMessages() const {
				return getFormattedErrorMessages();
			}

			std::string Reader::getFormattedErrorMessages() const {
				std::string formattedMessage;
				for (Errors::const_iterator itError = m_errors.begin();
					itError != m_errors.end();
					++itError) {
						const ErrorInfo& error = *itError;
						formattedMessage +=
							"* " + getLocationLineAndColumn(error.m_token.m_start) + "\n";
						formattedMessage += "  " + error.m_message + "\n";
						if (error.m_extra)
							formattedMessage +=
							"See " + getLocationLineAndColumn(error.m_extra) + " for detail.\n";
				}
				return formattedMessage;
			}

			std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
				std::vector<Reader::StructuredError> allErrors;
				for (Errors::const_iterator itError = m_errors.begin();
					itError != m_errors.end();
					++itError) {
						const ErrorInfo& error = *itError;
						Reader::StructuredError structured;
						structured.offset_start = error.m_token.m_start - m_begin;
						structured.offset_limit = error.m_token.m_end - m_begin;
						structured.message = error.m_message;
						allErrors.push_back(structured);
				}
				return allErrors;
			}

			bool Reader::pushError(const Value& value, const std::string& message) {
				size_t length = m_end - m_begin;
				if(value.getOffsetStart() > length
					|| value.getOffsetLimit() > length)
					return false;
				Token token;
				token.m_type = tokenError;
				token.m_start = m_begin + value.getOffsetStart();
				token.m_end = m_end + value.getOffsetLimit();
				ErrorInfo info;
				info.m_token = token;
				info.m_message = message;
				info.m_extra = 0;
				m_errors.push_back(info);
				return true;
			}

			bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
				size_t length = m_end - m_begin;
				if(value.getOffsetStart() > length
					|| value.getOffsetLimit() > length
					|| extra.getOffsetLimit() > length)
					return false;
				Token token;
				token.m_type = tokenError;
				token.m_start = m_begin + value.getOffsetStart();
				token.m_end = m_begin + value.getOffsetLimit();
				ErrorInfo info;
				info.m_token = token;
				info.m_message = message;
				info.m_extra = m_begin + extra.getOffsetStart();
				m_errors.push_back(info);
				return true;
			}

			bool Reader::good() const {
				return !m_errors.size();
			}

			// exact copy of Features
			class OurFeatures {
			public:
				static OurFeatures all();
				OurFeatures();
				bool m_allowComments;
				bool m_strictRoot;
				bool m_allowDroppedNullPlaceholders;
				bool m_allowNumericKeys;
				bool allowSingleQuotes_;
				bool failIfm_extra;
				bool rejectDupKeys_;
				int stackLimit_;
			};  // OurFeatures

			// exact copy of Implementation of class Features
			// ////////////////////////////////

			OurFeatures::OurFeatures()
				: m_allowComments(true), m_strictRoot(false)
				, m_allowDroppedNullPlaceholders(false), m_allowNumericKeys(false)
				, allowSingleQuotes_(false)
				, failIfm_extra(false)
			{
			}

			OurFeatures OurFeatures::all() { return OurFeatures(); }

			// Implementation of class Reader
			// ////////////////////////////////

			// exact copy of Reader, renamed to OurReader
			class OurReader {
			public:
				typedef char Char;
				typedef const Char* Location;
				struct StructuredError {
					size_t offset_start;
					size_t offset_limit;
					std::string message;
				};

				OurReader(OurFeatures const& features);
				bool parse(const char* beginDoc,
					const char* endDoc,
					Value& root,
					bool collectComments = true);
				std::string getFormattedErrorMessages() const;
				std::vector<StructuredError> getStructuredErrors() const;
				bool pushError(const Value& value, const std::string& message);
				bool pushError(const Value& value, const std::string& message, const Value& extra);
				bool good() const;

			private:
				OurReader(OurReader const&);  // no impl
				void operator=(OurReader const&);  // no impl

				enum TokenType {
					tokenEndOfStream = 0,
					tokenObjectBegin,
					tokenObjectEnd,
					tokenArrayBegin,
					tokenArrayEnd,
					tokenString,
					tokenNumber,
					tokenTrue,
					tokenFalse,
					tokenNull,
					tokenArraySeparator,
					tokenMemberSeparator,
					tokenComment,
					tokenError
				};

				class Token {
				public:
					TokenType m_type;
					Location m_start;
					Location m_end;
				};

				class ErrorInfo {
				public:
					Token m_token;
					std::string m_message;
					Location m_extra;
				};

				typedef std::deque<ErrorInfo> Errors;

				bool readToken(Token& token);
				void skipSpaces();
				bool match(Location pattern, int patternLength);
				bool readComment();
				bool readCStyleComment();
				bool readCppStyleComment();
				bool readString();
				bool readStringSingleQuote();
				void readNumber();
				bool readValue();
				bool readObject(Token& token);
				bool readArray(Token& token);
				bool decodeNumber(Token& token);
				bool decodeNumber(Token& token, Value& decoded);
				bool decodeString(Token& token);
				bool decodeString(Token& token, std::string& decoded);
				bool decodeDouble(Token& token);
				bool decodeDouble(Token& token, Value& decoded);
				bool decodeUnicodeCodePoint(Token& token,
					Location& current,
					Location end,
					unsigned int& unicode);
				bool decodeUnicodeEscapeSequence(Token& token,
					Location& current,
					Location end,
					unsigned int& unicode);
				bool addError(const std::string& message, Token& token, Location extra = 0);
				bool recoverFromError(TokenType skipUntilToken);
				bool addErrorAndRecover(const std::string& message,
					Token& token,
					TokenType skipUntilToken);
				void skipUntilSpace();
				Value& currentValue();
				Char getNextChar();
				void
					getLocationLineAndColumn(Location location, int& line, int& column) const;
				std::string getLocationLineAndColumn(Location location) const;
				void addComment(Location begin, Location end, CommentPlacement placement);
				void skipCommentTokens(Token& token);

				typedef std::stack<Value*> Nodes;
				Nodes m_nodes;
				Errors m_errors;
				std::string m_document;
				Location m_begin;
				Location m_end;
				Location m_current;
				Location m_lastValueEnd;
				Value* m_lastValue;
				std::string m_commentsBefore;
				int stackDepth_;

				OurFeatures const m_features;
				bool m_collectComments;
			};  // OurReader

			// complete copy of Read impl, for OurReader

			OurReader::OurReader(OurFeatures const& features)
				: m_errors(), m_document(), m_begin(), m_end(), m_current(), m_lastValueEnd(),
				m_lastValue(), m_commentsBefore(), m_features(features), m_collectComments() {
			}

			bool OurReader::parse(const char* beginDoc,
				const char* endDoc,
				Value& root,
				bool collectComments) {
					if (!m_features.m_allowComments) {
						collectComments = false;
					}

					m_begin = beginDoc;
					m_end = endDoc;
					m_collectComments = collectComments;
					m_current = m_begin;
					m_lastValueEnd = 0;
					m_lastValue = 0;
					m_commentsBefore = "";
					m_errors.clear();
					while (!m_nodes.empty())
						m_nodes.pop();
					m_nodes.push(&root);

					stackDepth_ = 0;
					bool successful = readValue();
					Token token;
					skipCommentTokens(token);
					if (m_features.failIfm_extra) {
						if (token.m_type != tokenError && token.m_type != tokenEndOfStream) {
							addError("Extra non-whitespace after JSON value.", token);
							return false;
						}
					}
					if (m_collectComments && !m_commentsBefore.empty())
						root.setComment(m_commentsBefore, commentAfter);
					if (m_features.m_strictRoot) {
						if (!root.isArray() && !root.isObject()) {
							// Set error location to start of doc, ideally should be first token found
							// in doc
							token.m_type = tokenError;
							token.m_start = beginDoc;
							token.m_end = endDoc;
							addError(
								"A valid JSON document must be either an array or an object value.",
								token);
							return false;
						}
					}
					return successful;
			}

			bool OurReader::readValue() {
				if (stackDepth_ >= m_features.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
				++stackDepth_;
				Token token;
				skipCommentTokens(token);
				bool successful = true;

				if (m_collectComments && !m_commentsBefore.empty()) {
					currentValue().setComment(m_commentsBefore, commentBefore);
					m_commentsBefore = "";
				}

				switch (token.m_type) {
  case tokenObjectBegin:
	  successful = readObject(token);
	  currentValue().setOffsetLimit(m_current - m_begin);
	  break;
  case tokenArrayBegin:
	  successful = readArray(token);
	  currentValue().setOffsetLimit(m_current - m_begin);
	  break;
  case tokenNumber:
	  successful = decodeNumber(token);
	  break;
  case tokenString:
	  successful = decodeString(token);
	  break;
  case tokenTrue:
	  {
		  Value v(true);
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(token.m_start - m_begin);
		  currentValue().setOffsetLimit(token.m_end - m_begin);
	  }
	  break;
  case tokenFalse:
	  {
		  Value v(false);
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(token.m_start - m_begin);
		  currentValue().setOffsetLimit(token.m_end - m_begin);
	  }
	  break;
  case tokenNull:
	  {
		  Value v;
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(token.m_start - m_begin);
		  currentValue().setOffsetLimit(token.m_end - m_begin);
	  }
	  break;
  case tokenArraySeparator:
  case tokenObjectEnd:
  case tokenArrayEnd:
	  if (m_features.m_allowDroppedNullPlaceholders) {
		  // "Un-read" the current token and mark the current value as a null
		  // token.
		  m_current--;
		  Value v;
		  currentValue().swapPayload(v);
		  currentValue().setOffsetStart(m_current - m_begin - 1);
		  currentValue().setOffsetLimit(m_current - m_begin);
		  break;
	  } // else, fall through ...
  default:
	  currentValue().setOffsetStart(token.m_start - m_begin);
	  currentValue().setOffsetLimit(token.m_end - m_begin);
	  return addError("Syntax error: value, object or array expected.", token);
				}

				if (m_collectComments) {
					m_lastValueEnd = m_current;
					m_lastValue = &currentValue();
				}

				--stackDepth_;
				return successful;
			}

			void OurReader::skipCommentTokens(Token& token) {
				if (m_features.m_allowComments) {
					do {
						readToken(token);
					} while (token.m_type == tokenComment);
				} else {
					readToken(token);
				}
			}

			bool OurReader::readToken(Token& token) {
				skipSpaces();
				token.m_start = m_current;
				Char c = getNextChar();
				bool ok = true;
				switch (c) {
  case '{':
	  token.m_type = tokenObjectBegin;
	  break;
  case '}':
	  token.m_type = tokenObjectEnd;
	  break;
  case '[':
	  token.m_type = tokenArrayBegin;
	  break;
  case ']':
	  token.m_type = tokenArrayEnd;
	  break;
  case '"':
	  token.m_type = tokenString;
	  ok = readString();
	  break;
  case '\'':
	  if (m_features.allowSingleQuotes_) {
		  token.m_type = tokenString;
		  ok = readStringSingleQuote();
		  break;
	  } // else continue
  case '/':
	  token.m_type = tokenComment;
	  ok = readComment();
	  break;
  case '0':
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9':
  case '-':
	  token.m_type = tokenNumber;
	  readNumber();
	  break;
  case 't':
	  token.m_type = tokenTrue;
	  ok = match("rue", 3);
	  break;
  case 'f':
	  token.m_type = tokenFalse;
	  ok = match("alse", 4);
	  break;
  case 'n':
	  token.m_type = tokenNull;
	  ok = match("ull", 3);
	  break;
  case ',':
	  token.m_type = tokenArraySeparator;
	  break;
  case ':':
	  token.m_type = tokenMemberSeparator;
	  break;
  case 0:
	  token.m_type = tokenEndOfStream;
	  break;
  default:
	  ok = false;
	  break;
				}
				if (!ok)
					token.m_type = tokenError;
				token.m_end = m_current;
				return true;
			}

			void OurReader::skipSpaces() {
				while (m_current != m_end) {
					Char c = *m_current;
					if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
						++m_current;
					else
						break;
				}
			}

			bool OurReader::match(Location pattern, int patternLength) {
				if (m_end - m_current < patternLength)
					return false;
				int index = patternLength;
				while (index--)
					if (m_current[index] != pattern[index])
						return false;
				m_current += patternLength;
				return true;
			}

			bool OurReader::readComment() {
				Location commentBegin = m_current - 1;
				Char c = getNextChar();
				bool successful = false;
				if (c == '*')
					successful = readCStyleComment();
				else if (c == '/')
					successful = readCppStyleComment();
				if (!successful)
					return false;

				if (m_collectComments) {
					CommentPlacement placement = commentBefore;
					if (m_lastValueEnd && !containsNewLine(m_lastValueEnd, commentBegin)) {
						if (c != '*' || !containsNewLine(commentBegin, m_current))
							placement = commentAfterOnSameLine;
					}

					addComment(commentBegin, m_current, placement);
				}
				return true;
			}

			void
				OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
					assert(m_collectComments);
					const std::string& normalized = normalizeEOL(begin, end);
					if (placement == commentAfterOnSameLine) {
						assert(m_lastValue != 0);
						m_lastValue->setComment(normalized, placement);
					} else {
						m_commentsBefore += normalized;
					}
			}

			bool OurReader::readCStyleComment() {
				while (m_current != m_end) {
					Char c = getNextChar();
					if (c == '*' && *m_current == '/')
						break;
				}
				return getNextChar() == '/';
			}

			bool OurReader::readCppStyleComment() {
				while (m_current != m_end) {
					Char c = getNextChar();
					if (c == '\n')
						break;
					if (c == '\r') {
						// Consume DOS EOL. It will be normalized in addComment.
						if (m_current != m_end && *m_current == '\n')
							getNextChar();
						// Break on Moc OS 9 EOL.
						break;
					}
				}
				return true;
			}

			void OurReader::readNumber() {
				const char *p = m_current;
				char c = '0'; // stopgap for already consumed character
				// integral part
				while (c >= '0' && c <= '9')
					c = (m_current = p) < m_end ? *p++ : 0;
				// fractional part
				if (c == '.') {
					c = (m_current = p) < m_end ? *p++ : 0;
					while (c >= '0' && c <= '9')
						c = (m_current = p) < m_end ? *p++ : 0;
				}
				// exponential part
				if (c == 'e' || c == 'E') {
					c = (m_current = p) < m_end ? *p++ : 0;
					if (c == '+' || c == '-')
						c = (m_current = p) < m_end ? *p++ : 0;
					while (c >= '0' && c <= '9')
						c = (m_current = p) < m_end ? *p++ : 0;
				}
			}
			bool OurReader::readString() {
				Char c = 0;
				while (m_current != m_end) {
					c = getNextChar();
					if (c == '\\')
						getNextChar();
					else if (c == '"')
						break;
				}
				return c == '"';
			}


			bool OurReader::readStringSingleQuote() {
				Char c = 0;
				while (m_current != m_end) {
					c = getNextChar();
					if (c == '\\')
						getNextChar();
					else if (c == '\'')
						break;
				}
				return c == '\'';
			}

			bool OurReader::readObject(Token& tokenStart) {
				Token tokenName;
				std::string name;
				Value init(objectValue);
				currentValue().swapPayload(init);
				currentValue().setOffsetStart(tokenStart.m_start - m_begin);
				while (readToken(tokenName)) {
					bool initialTokenOk = true;
					while (tokenName.m_type == tokenComment && initialTokenOk)
						initialTokenOk = readToken(tokenName);
					if (!initialTokenOk)
						break;
					if (tokenName.m_type == tokenObjectEnd && name.empty()) // empty object
						return true;
					name = "";
					if (tokenName.m_type == tokenString) {
						if (!decodeString(tokenName, name))
							return recoverFromError(tokenObjectEnd);
					} else if (tokenName.m_type == tokenNumber && m_features.m_allowNumericKeys) {
						Value numberName;
						if (!decodeNumber(tokenName, numberName))
							return recoverFromError(tokenObjectEnd);
						name = numberName.asString();
					} else {
						break;
					}

					Token colon;
					if (!readToken(colon) || colon.m_type != tokenMemberSeparator) {
						return addErrorAndRecover(
							"Missing ':' after object member name", colon, tokenObjectEnd);
					}
					if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
					if (m_features.rejectDupKeys_ && currentValue().isMember(name)) {
						std::string msg = "Duplicate key: '" + name + "'";
						return addErrorAndRecover(
							msg, tokenName, tokenObjectEnd);
					}
					Value& value = currentValue()[name];
					m_nodes.push(&value);
					bool ok = readValue();
					m_nodes.pop();
					if (!ok) // error already set
						return recoverFromError(tokenObjectEnd);

					Token comma;
					if (!readToken(comma) ||
						(comma.m_type != tokenObjectEnd && comma.m_type != tokenArraySeparator &&
						comma.m_type != tokenComment)) {
							return addErrorAndRecover(
								"Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
					}
					bool finalizeTokenOk = true;
					while (comma.m_type == tokenComment && finalizeTokenOk)
						finalizeTokenOk = readToken(comma);
					if (comma.m_type == tokenObjectEnd)
						return true;
				}
				return addErrorAndRecover(
					"Missing '}' or object member name", tokenName, tokenObjectEnd);
			}

			bool OurReader::readArray(Token& tokenStart) {
				Value init(arrayValue);
				currentValue().swapPayload(init);
				currentValue().setOffsetStart(tokenStart.m_start - m_begin);
				skipSpaces();
				if (*m_current == ']') // empty array
				{
					Token endArray;
					readToken(endArray);
					return true;
				}
				int index = 0;
				for (;;) {
					Value& value = currentValue()[index++];
					m_nodes.push(&value);
					bool ok = readValue();
					m_nodes.pop();
					if (!ok) // error already set
						return recoverFromError(tokenArrayEnd);

					Token token;
					// Accept Comment after last item in the array.
					ok = readToken(token);
					while (token.m_type == tokenComment && ok) {
						ok = readToken(token);
					}
					bool badTokenType =
						(token.m_type != tokenArraySeparator && token.m_type != tokenArrayEnd);
					if (!ok || badTokenType) {
						return addErrorAndRecover(
							"Missing ',' or ']' in array declaration", token, tokenArrayEnd);
					}
					if (token.m_type == tokenArrayEnd)
						break;
				}
				return true;
			}

			bool OurReader::decodeNumber(Token& token) {
				Value decoded;
				if (!decodeNumber(token, decoded))
					return false;
				currentValue().swapPayload(decoded);
				currentValue().setOffsetStart(token.m_start - m_begin);
				currentValue().setOffsetLimit(token.m_end - m_begin);
				return true;
			}

			bool OurReader::decodeNumber(Token& token, Value& decoded) {
				// Attempts to parse the number as an integer. If the number is
				// larger than the maximum supported value of an integer then
				// we decode the number as a double.
				Location current = token.m_start;
				bool isNegative = *current == '-';
				if (isNegative)
					++current;
				// TODO: Help the compiler do the div and mod at compile time or get rid of them.
				Value::LargestUInt maxIntegerValue =
					isNegative ? Value::LargestUInt(-Value::minLargestInt)
					: Value::maxLargestUInt;
				Value::LargestUInt threshold = maxIntegerValue / 10;
				Value::LargestUInt value = 0;
				while (current < token.m_end) {
					Char c = *current++;
					if (c < '0' || c > '9')
						return decodeDouble(token, decoded);
					Value::UInt digit(c - '0');
					if (value >= threshold) {
						// We've hit or exceeded the max value divided by 10 (rounded down). If
						// a) we've only just touched the limit, b) this is the last digit, and
						// c) it's small enough to fit in that rounding delta, we're okay.
						// Otherwise treat this number as a double to avoid overflow.
						if (value > threshold || current != token.m_end ||
							digit > maxIntegerValue % 10) {
								return decodeDouble(token, decoded);
						}
					}
					value = value * 10 + digit;
				}
				if (isNegative)
					decoded = -Value::LargestInt(value);
				else if (value <= Value::LargestUInt(Value::maxInt))
					decoded = Value::LargestInt(value);
				else
					decoded = value;
				return true;
			}

			bool OurReader::decodeDouble(Token& token) {
				Value decoded;
				if (!decodeDouble(token, decoded))
					return false;
				currentValue().swapPayload(decoded);
				currentValue().setOffsetStart(token.m_start - m_begin);
				currentValue().setOffsetLimit(token.m_end - m_begin);
				return true;
			}

			bool OurReader::decodeDouble(Token& token, Value& decoded) {
				double value = 0;
				const int bufferSize = 32;
				int count;
				int length = int(token.m_end - token.m_start);

				// Sanity check to avoid buffer overflow exploits.
				if (length < 0) {
					return addError("Unable to parse token length", token);
				}

				// Avoid using a string constant for the format control string given to
				// sscanf, as this can cause hard to debug crashes on OS X. See here for more
				// info:
				//
				//     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
				char format[] = "%lf";

				if (length <= bufferSize) {
					Char buffer[bufferSize + 1];
					memcpy(buffer, token.m_start, length);
					buffer[length] = 0;
					count = sscanf(buffer, format, &value);
				} else {
					std::string buffer(token.m_start, token.m_end);
					count = sscanf(buffer.c_str(), format, &value);
				}

				if (count != 1)
					return addError("'" + std::string(token.m_start, token.m_end) +
					"' is not a number.",
					token);
				decoded = value;
				return true;
			}

			bool OurReader::decodeString(Token& token) {
				std::string decoded_string;
				if (!decodeString(token, decoded_string))
					return false;
				Value decoded(decoded_string);
				currentValue().swapPayload(decoded);
				currentValue().setOffsetStart(token.m_start - m_begin);
				currentValue().setOffsetLimit(token.m_end - m_begin);
				return true;
			}

			bool OurReader::decodeString(Token& token, std::string& decoded) {
				decoded.reserve(token.m_end - token.m_start - 2);
				Location current = token.m_start + 1; // skip '"'
				Location end = token.m_end - 1;       // do not include '"'
				while (current != end) {
					Char c = *current++;
					if (c == '"')
						break;
					else if (c == '\\') {
						if (current == end)
							return addError("Empty escape sequence in string", token, current);
						Char escape = *current++;
						switch (escape) {
	  case '"':
		  decoded += '"';
		  break;
	  case '/':
		  decoded += '/';
		  break;
	  case '\\':
		  decoded += '\\';
		  break;
	  case 'b':
		  decoded += '\b';
		  break;
	  case 'f':
		  decoded += '\f';
		  break;
	  case 'n':
		  decoded += '\n';
		  break;
	  case 'r':
		  decoded += '\r';
		  break;
	  case 't':
		  decoded += '\t';
		  break;
	  case 'u': {
		  unsigned int unicode;
		  if (!decodeUnicodeCodePoint(token, current, end, unicode))
			  return false;
		  decoded += codePointToUTF8(unicode);
				} break;
	  default:
		  return addError("Bad escape sequence in string", token, current);
						}
					} else {
						decoded += c;
					}
				}
				return true;
			}

			bool OurReader::decodeUnicodeCodePoint(Token& token,
				Location& current,
				Location end,
				unsigned int& unicode) {

					if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
						return false;
					if (unicode >= 0xD800 && unicode <= 0xDBFF) {
						// surrogate pairs
						if (end - current < 6)
							return addError(
							"additional six characters expected to parse unicode surrogate pair.",
							token,
							current);
						unsigned int surrogatePair;
						if (*(current++) == '\\' && *(current++) == 'u') {
							if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
								unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
							} else
								return false;
						} else
							return addError("expecting another \\u token to begin the second half of "
							"a unicode surrogate pair",
							token,
							current);
					}
					return true;
			}

			bool OurReader::decodeUnicodeEscapeSequence(Token& token,
				Location& current,
				Location end,
				unsigned int& unicode) {
					if (end - current < 4)
						return addError(
						"Bad unicode escape sequence in string: four digits expected.",
						token,
						current);
					unicode = 0;
					for (int index = 0; index < 4; ++index) {
						Char c = *current++;
						unicode *= 16;
						if (c >= '0' && c <= '9')
							unicode += c - '0';
						else if (c >= 'a' && c <= 'f')
							unicode += c - 'a' + 10;
						else if (c >= 'A' && c <= 'F')
							unicode += c - 'A' + 10;
						else
							return addError(
							"Bad unicode escape sequence in string: hexadecimal digit expected.",
							token,
							current);
					}
					return true;
			}

			bool
				OurReader::addError(const std::string& message, Token& token, Location extra) {
					ErrorInfo info;
					info.m_token = token;
					info.m_message = message;
					info.m_extra = extra;
					m_errors.push_back(info);
					return false;
			}

			bool OurReader::recoverFromError(TokenType skipUntilToken) {
				int errorCount = int(m_errors.size());
				Token skip;
				for (;;) {
					if (!readToken(skip))
						m_errors.resize(errorCount); // discard errors caused by recovery
					if (skip.m_type == skipUntilToken || skip.m_type == tokenEndOfStream)
						break;
				}
				m_errors.resize(errorCount);
				return false;
			}

			bool OurReader::addErrorAndRecover(const std::string& message,
				Token& token,
				TokenType skipUntilToken) {
					addError(message, token);
					return recoverFromError(skipUntilToken);
			}

			Value& OurReader::currentValue() { return *(m_nodes.top()); }

			OurReader::Char OurReader::getNextChar() {
				if (m_current == m_end)
					return 0;
				return *m_current++;
			}

			void OurReader::getLocationLineAndColumn(Location location,
				int& line,
				int& column) const {
					Location current = m_begin;
					Location lastLineStart = current;
					line = 0;
					while (current < location && current != m_end) {
						Char c = *current++;
						if (c == '\r') {
							if (*current == '\n')
								++current;
							lastLineStart = current;
							++line;
						} else if (c == '\n') {
							lastLineStart = current;
							++line;
						}
					}
					// column & line start at 1
					column = int(location - lastLineStart) + 1;
					++line;
			}

			std::string OurReader::getLocationLineAndColumn(Location location) const {
				int line, column;
				getLocationLineAndColumn(location, line, column);
				char buffer[18 + 16 + 16 + 1];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
#if defined(WINCE)
				_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#else
				sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
#else
				snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
				return buffer;
			}

			std::string OurReader::getFormattedErrorMessages() const {
				std::string formattedMessage;
				for (Errors::const_iterator itError = m_errors.begin();
					itError != m_errors.end();
					++itError) {
						const ErrorInfo& error = *itError;
						formattedMessage +=
							"* " + getLocationLineAndColumn(error.m_token.m_start) + "\n";
						formattedMessage += "  " + error.m_message + "\n";
						if (error.m_extra)
							formattedMessage +=
							"See " + getLocationLineAndColumn(error.m_extra) + " for detail.\n";
				}
				return formattedMessage;
			}

			std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
				std::vector<OurReader::StructuredError> allErrors;
				for (Errors::const_iterator itError = m_errors.begin();
					itError != m_errors.end();
					++itError) {
						const ErrorInfo& error = *itError;
						OurReader::StructuredError structured;
						structured.offset_start = error.m_token.m_start - m_begin;
						structured.offset_limit = error.m_token.m_end - m_begin;
						structured.message = error.m_message;
						allErrors.push_back(structured);
				}
				return allErrors;
			}

			bool OurReader::pushError(const Value& value, const std::string& message) {
				size_t length = m_end - m_begin;
				if(value.getOffsetStart() > length
					|| value.getOffsetLimit() > length)
					return false;
				Token token;
				token.m_type = tokenError;
				token.m_start = m_begin + value.getOffsetStart();
				token.m_end = m_end + value.getOffsetLimit();
				ErrorInfo info;
				info.m_token = token;
				info.m_message = message;
				info.m_extra = 0;
				m_errors.push_back(info);
				return true;
			}

			bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) {
				size_t length = m_end - m_begin;
				if(value.getOffsetStart() > length
					|| value.getOffsetLimit() > length
					|| extra.getOffsetLimit() > length)
					return false;
				Token token;
				token.m_type = tokenError;
				token.m_start = m_begin + value.getOffsetStart();
				token.m_end = m_begin + value.getOffsetLimit();
				ErrorInfo info;
				info.m_token = token;
				info.m_message = message;
				info.m_extra = m_begin + extra.getOffsetStart();
				m_errors.push_back(info);
				return true;
			}

			bool OurReader::good() const {
				return !m_errors.size();
			}


			class OurCharReader : public CharReader {
				bool const m_collectComments;
				OurReader reader_;
			public:
				OurCharReader(
					bool collectComments,
					OurFeatures const& features)
					: m_collectComments(collectComments)
					, reader_(features)
				{}
				virtual bool parse(
					char const* beginDoc, char const* endDoc,
					Value* root, std::string* errs) {
						bool ok = reader_.parse(beginDoc, endDoc, *root, m_collectComments);
						if (errs) {
							*errs = reader_.getFormattedErrorMessages();
						}
						return ok;
				}
			};

			CharReaderBuilder::CharReaderBuilder()
			{
				setDefaults(&m_settings);
			}
			CharReaderBuilder::~CharReaderBuilder()
			{}
			CharReader* CharReaderBuilder::newCharReader() const
			{
				bool collectComments = m_settings["collectComments"].asBool();
				OurFeatures features = OurFeatures::all();
				features.m_allowComments = m_settings["allowComments"].asBool();
				features.m_strictRoot = m_settings["strictRoot"].asBool();
				features.m_allowDroppedNullPlaceholders = m_settings["allowDroppedNullPlaceholders"].asBool();
				features.m_allowNumericKeys = m_settings["allowNumericKeys"].asBool();
				features.allowSingleQuotes_ = m_settings["allowSingleQuotes"].asBool();
				features.stackLimit_ = m_settings["stackLimit"].asInt();
				features.failIfm_extra = m_settings["failIfExtra"].asBool();
				features.rejectDupKeys_ = m_settings["rejectDupKeys"].asBool();
				return new OurCharReader(collectComments, features);
			}
			static void getValidReaderKeys(std::set<std::string>* valid_keys)
			{
				valid_keys->clear();
				valid_keys->insert("collectComments");
				valid_keys->insert("allowComments");
				valid_keys->insert("strictRoot");
				valid_keys->insert("allowDroppedNullPlaceholders");
				valid_keys->insert("allowNumericKeys");
				valid_keys->insert("allowSingleQuotes");
				valid_keys->insert("stackLimit");
				valid_keys->insert("failIfExtra");
				valid_keys->insert("rejectDupKeys");
			}
			bool CharReaderBuilder::validate(Value* invalid) const
			{
				Value my_invalid;
				if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
				Value& inv = *invalid;
				std::set<std::string> valid_keys;
				getValidReaderKeys(&valid_keys);
				Value::Members keys = m_settings.getMemberNames();
				size_t n = keys.size();
				for (size_t i = 0; i < n; ++i) {
					std::string const& key = keys[i];
					if (valid_keys.find(key) == valid_keys.end()) {
						inv[key] = m_settings[key];
					}
				}
				return 0u == inv.size();
			}
			Value& CharReaderBuilder::operator[](std::string key)
			{
				return m_settings[key];
			}
			// static
			void CharReaderBuilder::strictMode(Value* settings)
			{
				//! [CharReaderBuilderStrictMode]
				(*settings)["allowComments"] = false;
				(*settings)["strictRoot"] = true;
				(*settings)["allowDroppedNullPlaceholders"] = false;
				(*settings)["allowNumericKeys"] = false;
				(*settings)["allowSingleQuotes"] = false;
				(*settings)["failIfExtra"] = true;
				(*settings)["rejectDupKeys"] = true;
				//! [CharReaderBuilderStrictMode]
			}
			// static
			void CharReaderBuilder::setDefaults(Value* settings)
			{
				//! [CharReaderBuilderDefaults]
				(*settings)["collectComments"] = true;
				(*settings)["allowComments"] = true;
				(*settings)["strictRoot"] = false;
				(*settings)["allowDroppedNullPlaceholders"] = false;
				(*settings)["allowNumericKeys"] = false;
				(*settings)["allowSingleQuotes"] = false;
				(*settings)["stackLimit"] = 1000;
				(*settings)["failIfExtra"] = false;
				(*settings)["rejectDupKeys"] = false;
				//! [CharReaderBuilderDefaults]
			}

			//////////////////////////////////
			// global functions

			bool parseFromStream(
				CharReader::Factory const& fact, std::istream& sin,
				Value* root, std::string* errs)
			{
				std::ostringstream ssin;
				ssin << sin.rdbuf();
				std::string doc = ssin.str();
				char const* begin = doc.data();
				char const* end = begin + doc.size();
				// Note that we do not actually need a null-terminator.
				CharReaderPtr const reader(fact.newCharReader());
				return reader->parse(begin, end, root, errs);
			}

			std::istream& operator>>(std::istream& sin, Value& root) {
				CharReaderBuilder b;
				std::string errs;
				bool ok = parseFromStream(b, sin, &root, &errs);
				if (!ok) {
					fprintf(stderr,
						"Error from reader: %s",
						errs.c_str());

					throwRuntimeError("reader error");
				}
				return sin;
			}
		}//end namespace jsoncpp
	}//end namespace json
}//end namespace JHCPP
